home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
pcr
/
pcr4_4.lha
/
DIST
/
debugnub
/
CirioNubRuntime.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-04
|
18KB
|
773 lines
/* begincopyright
Copyright (c) 1988 Xerox Corporation. All rights reserved.
Use and copying of this software and preparation of derivative works based
upon this software are permitted. Any distribution of this software or
derivative works must comply with all applicable United States export
control laws. This software is made available AS IS, and Xerox Corporation
makes no warranty about the software, its performance or its conformity to
any specification. Any person obtaining a copy of this software is requested
to send their name and post office or electronic mail address to:
PCR Coordinator
Xerox PARC
3333 Coyote Hill Rd.
Palo Alto, CA 94304
endcopyright */
/*
* CirioNubRuntime.c
*
* Demers, February 20, 1990 3:56:47 pm PST
* Agostino, June 12, 1991 9:40:02 am PDT
*/
#include "xr/Errno.h"
#include "xr/ThreadsBackdoor.h"
#include "xr/ThreadsSlaveIOP.h"
#include "xr/ThreadsSignalsPrivate.h"
#include "xr/CirioNubProtocol.h"
#include "xr/CirioNubPrivate.h"
#include "xr/CirioNubInstall.h"
#include "xr/CirioNubMarshall.h"
#include "xr/ThreadsMsg.h"
#include <sys/socket.h>
#include <netinet/tcp.h>
extern int errno;
/*
* Global state on slave processor
*/
static CirioNubData cnd;
/*
* Debugging messages
*/
void CirioDBM(fmt, x1, x2, x3, x4, x5)
char *fmt;
int x1, x2, x3, x4, x5;
{
static int gotEnv = FALSE;
static int pcm;
if( !gotEnv ) {
extern char *(getenv());
char *env = getenv("CirioPrintConsoleMessages");
pcm = (env != NIL);
gotEnv = TRUE;
}
if( pcm ) XR_ConsoleMsg(fmt, x1, x2, x3, x4, x5);
}
/*
* Marshalling stuff
*/
/*
wait for descriptor ready (or just wait if descriptor < 0).
Return 0 on timeout, 1 if ready, (-errno) on error.
Note the error may be EINTR.
*/
static int
CirioNubWaitDescriptorReady(fd, in, mSecs)
int fd;
bool in;
unsigned mSecs;
{
struct timeval timeout;
int fdBuf;
int *ip = NIL;
int *op = NIL;
int *xp = NIL;
int ans;
timeout.tv_sec = mSecs/1000;
timeout.tv_usec = (mSecs % 1000) * 1000;
if( fd >= 0 ) {
fdBuf = 01 << fd;
if( in ) ip = &fdBuf; else op = &fdBuf;
}
ans = select(32, ip, op, xp, &timeout);
return ((ans >= 0) ? ans : (-errno));
}
/*
accept
*/
static int
CirioNubAccept(fd, ap, lenp)
int fd;
struct sockaddr_in *ap;
int *lenp;
{
int ans;
int savedLen = *lenp;
XR_SignalState oldState;
oldState = XR_EnableSignals();
for(;;) {
ans = CirioNubWaitDescriptorReady(fd, TRUE, 5000);
if( ans <= 0 ) {
if( (ans < 0) && (ans != (-EINTR)) ) break;
} else {
*lenp = savedLen;
ans = accept(fd, ap, lenp);
if( ans < 0 ) ans = (-errno);
if( ans != (-EINTR) ) break;
}
}
XR_SetSignalState(oldState);
return ans;
}
/*
read/write without returning short result
*/
static CirioNubRetCode
CirioNubDoIOUntilDone(fd, in, buf, nBytes)
int fd;
bool in;
char *buf;
int nBytes;
{
int ans;
CirioNubRetCode retCode = cnrc_comm;
XR_SignalState oldState;
oldState = XR_EnableSignals();
for(;;) {
ans = CirioNubWaitDescriptorReady(fd, in, 5000);
if( (ans == 0) || (ans == (-EINTR)) ) continue;
ans = (in ? read(fd, buf, nBytes) : write(fd, buf, nBytes));
if( ans < 0 ) ans = (-errno);
if( ans == (-EINTR) ) continue;
if( ans < 0 ) break;
if( (ans == 0) && in ) break;
nBytes -= ans;
buf += ans;
if( nBytes <= 0 ) { retCode = cnrc_ok; break; }
}
Out:
XR_SetSignalState(oldState);
return retCode;
}
#define readall(fd, buf, nBytes) \
CirioNubDoIOUntilDone((fd), TRUE, (buf), (nBytes))
#define writeall(fd, buf, nBytes) \
CirioNubDoIOUntilDone((fd), FALSE, (buf), (nBytes))
/*
* Send data with type info
*/
static CirioNubRetCode
CirioNubPut32Inner(n, tag)
unsigned n;
enum CirioNubTag tag;
{
struct {
struct CirioNubWrapper w;
net_long x;
} buf;
buf.w.cnw_tag = htons(((short)(tag)));
buf.w.cnw_len = htons( (sizeof n) );
buf.x = htonl(n);
return writeall(cnd->cnd_rpcFD, &buf, (sizeof buf));
}
#define CirioNubPutRetCode(c) CirioNubPut32Inner(((unsigned)(c)),cnt_retCode)
#define CirioNubPutProcID(id) CirioNubPut32Inner(((unsigned)(id)),cnt_procID)
CirioNubRetCode
CirioNubPutCard32(n)
unsigned n;
{
return CirioNubPut32Inner(((unsigned)(n)), cnt_card32);
}
CirioNubRetCode
CirioNubPutInt32(n)
int n;
{
return CirioNubPut32Inner(((unsigned)(n)), cnt_int32);
}
static CirioNubRetCode
CirioNubPutBlock8Inner(b, len, tag)
char *b;
int len;
enum CirioNubTag tag;
{
struct CirioNubWrapper w;
CirioNubRetCode ans;
w.cnw_tag = htons(((short)(tag)));
w.cnw_len = htons(len);
if( (ans = writeall(cnd->cnd_rpcFD, &w, (sizeof w))) != cnrc_ok ) {
return(ans);
}
if( len == 0 ) return(cnrc_ok);
if( (ans = writeall(cnd->cnd_rpcFD, b, len)) != cnrc_ok ) {
return(ans);
}
if( len & 03 ) {
int slop = 4 - (len & 03);
int zero = 0;
if( (ans = writeall(cnd->cnd_rpcFD, &zero, slop)) != cnrc_ok ) {
return(ans);
}
}
return(cnrc_ok);
}
CirioNubRetCode
CirioNubPutString(s)
char *s;
{
return( CirioNubPutBlock8Inner(s, strlen(s), cnt_string) );
}
CirioNubRetCode
CirioNubPutBlock8(b, len)
char *b;
int len;
{
return( CirioNubPutBlock8Inner(b, len, cnt_block8) );
}
CirioNubRetCode
CirioNubPutBlock16(b, len)
short *b;
int len;
{
struct CirioNubWrapper w;
CirioNubRetCode ans;
int zero = 0;
b = (short *)(((unsigned)(b)) & (~01));
len = (len + 1) & (~01);
w.cnw_tag = htons(cnt_block16);
w.cnw_len = htons(len);
/* removed extra call to writeall -- mna 6/12/91 */
if( (ans = writeall(cnd->cnd_rpcFD, &w, (sizeof w))) != cnrc_ok ) {
return(ans);
}
if( len == 0 ) return(cnrc_ok);
if( htons(1) != 1 ) {
int cnt = len;
short *p = b;
while( cnt > 0 ) { *p = htons(*p); p++; cnt-= 2; }
}
if( (ans = writeall(cnd->cnd_rpcFD, b, len)) == cnrc_ok ) {
if( (len & 03) != 0 ) {
ans = writeall(cnd->cnd_rpcFD, &zero, 2);
}
}
if( htons(1) != 1 ) {
int cnt = len;
short *p = b;
while( cnt > 0 ) { *p = ntohs(*p); p++; cnt-= 2; }
}
return( ans );
}
CirioNubRetCode
CirioNubPutBlock32(b, len)
long *b;
int len;
{
struct CirioNubWrapper w;
CirioNubRetCode ans;
b = (long *)(((unsigned)(b)) & (~03));
len = (len + 3) & (~03);
w.cnw_tag = htons(cnt_block32);
w.cnw_len = htons(len);
if( (ans = writeall(cnd->cnd_rpcFD, &w, (sizeof w))) != cnrc_ok ) {
return(ans);
}
if( len == 0 ) return(cnrc_ok);
if( htons(1) != 1 ) {
int cnt = len;
long *p = b;
while( cnt > 0 ) { *p = htonl(*p); p++; cnt-= 4; }
}
ans = writeall(cnd->cnd_rpcFD, b, len);
if( htons(1) != 1 ) {
int cnt = len;
long *p = b;
while( cnt > 0 ) { *p = ntohl(*p); p++; cnt-= 4; }
}
return( ans );
}
CirioNubRetCode
CirioNubGetCard32(b)
unsigned *b;
{
CirioNubRetCode ans;
unsigned buf;
if( (ans = readall(cnd->cnd_rpcFD, &buf, (sizeof buf))) != cnrc_ok )
return(ans);
*b = ntohl(buf);
return(cnrc_ok);
}
#define CirioNubGetInt32(b) CirioNubGetCard32( ((unsigned *)(b)) )
/* all lengths below are rounded up to full 32-bit words */
CirioNubRetCode
CirioNubGetBlock8(b, len)
char *b;
int len;
{
len = (len + 3) & (~03);
return( readall(cnd->cnd_rpcFD, b, len) );
}
CirioNubRetCode
CirioNubGetBlock16(b, len)
short *b;
int len;
{
CirioNubRetCode ans;
if( len == 0 ) return(cnrc_ok);
b = (short *)(((unsigned)(b)) & (~01));
len = (len + 3) & (~03);
if( (ans = readall(cnd->cnd_rpcFD, b, len)) != cnrc_ok ) return(ans);
if( htons(1) != 1 ) {
while( len > 0 ) { *b = ntohs(*b); b++; len -= 2; }
}
return(cnrc_ok);
}
CirioNubRetCode
CirioNubGetBlock32(b, len)
long *b;
int len;
{
CirioNubRetCode ans;
if( len == 0 ) return(cnrc_ok);
b = (long *)(((unsigned)(b)) & (~03));
len = (len + 3) & (~03);
if( (ans = readall(cnd->cnd_rpcFD, b, len)) != cnrc_ok ) return(ans);
if( htonl(1) != 1 ) {
while( len > 0 ) { *b = ntohl(*b); b++; len -= 4; }
}
return(cnrc_ok);
}
#define HASH(d,id) ((id) & ((d)->cnd_numHdrs-1))
static CirioNubRetCode
CirioNubDispatch(procID, argc, argp)
int procID;
int argc;
unsigned *argp;
{
struct CirioNubProcEntry *cnpe;
enum CirioNubRetCode retCode, ans;
retCode = cnrc_noProc;
for( cnpe = cnd->cnd_procEntries[HASH(cnd,procID)]
; cnpe != NIL
; cnpe = cnpe->cnpe_next
) {
if( cnpe->cnpe_procID == procID ) {
retCode = (
(cnpe->cnpe_clientData == NIL)
? (*(cnpe->cnpe_proc))(argc, argp)
: (*(cnpe->cnpe_proc))(argc, argp, cnpe->cnpe_clientData)
);
break;
}
}
if( retCode < cnrc_MUST_CLOSE_CONNECTION ) {
if( (ans = CirioNubPutRetCode(retCode)) != cnrc_ok ) retCode = ans;
}
return( retCode );
}
static CirioNubRetCode
CirioNubProcessCall()
{
CirioNubRetCode ans;
struct CirioNubWrapper w;
unsigned procID;
int len, roundedLen, roundedLenWithNull;
char *p;
unsigned *argp;
unsigned *buffer = ((unsigned *)(cnd->cnd_callBuf));
# define NEEDSPACE(n) \
if ( (((char *)(argp)) + (n)) > p ) { ans = cnrc_space; goto Out; }
argp = buffer;
p = ((char *)(buffer)) + (cnd->cnd_callBufBytes);
CirioDBM("Cirio-> ");
for(;;) {
if( (ans = readall(cnd->cnd_rpcFD, &w, (sizeof w))) != cnrc_ok ) {
CirioDBM("Cirio bad read %d\n", ans);
goto Out;
}
CirioDBM(". ");
len = (int)(ntohs(w.cnw_len));
roundedLen = (len + 03) & (~03);
switch( ntohs(w.cnw_tag) ) {
case cnt_procID:
if( (ans = CirioNubGetCard32(&procID)) == cnrc_ok ) {
# ifdef GCNOTINTHREAD
if( XR_sysArea->sa_heapNum != XR_iope->iope_heapNum ) {
/* update heap memory map */
/* (order of following two lines is important!) */
XR_iope->iope_heapNum = XR_sysArea->sa_heapNum;
XR_MapSeg2( &(XR_iope->iope_seg),
&(XR_sysArea->sa_heapSeg) );
}
# endif
CirioDBM("proc %d ", procID);
ans = CirioNubDispatch(procID, (argp-buffer), buffer);
}
goto Out;
case cnt_card32:
NEEDSPACE((sizeof *argp));
if( (ans = CirioNubGetCard32(argp)) != cnrc_ok ) goto Out;
argp++;
break;
case cnt_int32:
NEEDSPACE((sizeof *argp));
if( (ans = CirioNubGetInt32(argp)) != cnrc_ok ) goto Out;
argp++;
break;
case cnt_string: {
roundedLenWithNull = (len + 04) & (~03);
NEEDSPACE(roundedLenWithNull+(sizeof *argp));
p -= roundedLenWithNull;
if( (ans = CirioNubGetBlock8(p, roundedLen)) != cnrc_ok )
goto Out;
p[len] = 0;
*argp++ = (unsigned)(p);
}
break;
case cnt_block8:
NEEDSPACE(roundedLen+2*(sizeof *argp));
p -= roundedLen;
if( (ans = CirioNubGetBlock8(p, roundedLen)) != cnrc_ok )
goto Out;
*argp++ = len;
*argp++ = (unsigned)(p);
break;
case cnt_block16:
NEEDSPACE(roundedLen+2*(sizeof *argp));
p -= roundedLen;
if( (ans = CirioNubGetBlock16(p, roundedLen)) != cnrc_ok )
goto Out;
*argp++ = len;
*argp++ = (unsigned)(p);
break;
case cnt_block32:
NEEDSPACE(roundedLen+2*(sizeof *argp));
p -= roundedLen;
if( (ans = CirioNubGetBlock32(p, roundedLen)) != cnrc_ok )
goto Out;
*argp++ = len;
*argp++ = (unsigned)(p);
break;
default:
ans = cnrc_protocol;
goto Out;
}
}
Out:
CirioDBM("-> Cirio (%d)\n", ans);
return ans;
}
#undef NEEDSPACE
int
CirioNubSlaveSleep(mSecs)
unsigned mSecs;
{
XR_SignalState oldState;
oldState = XR_EnableSignals();
for(;;) {
if( CirioNubWaitDescriptorReady(-1, TRUE, mSecs) != (-EINTR) ) break;
}
XR_SetSignalState(oldState);
}
static bool
CirioNubWorkerProc()
{
CirioNubRetCode retCode;
int one = 1;
if( cnd->cnd_rpcFD < 0 ) {
struct sockaddr_in hisAddr;
int hisAddrLen = (sizeof hisAddr);
int fd = CirioNubAccept(cnd->cnd_listenerFD, &hisAddr, &hisAddrLen);
if( fd < 0 ) {
(void)CirioNubSlaveSleep(2000);
return TRUE;
}
(void) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, (sizeof one));
cnd->cnd_rpcFD = fd;
XR_ConsoleMsg("CirioNubWorkerProc got connection\n");
}
while( (retCode = CirioNubProcessCall()) == cnrc_ok ) continue;
if( retCode < cnrc_MUST_CLOSE_CONNECTION ) {
return TRUE;
} else {
(void)close(cnd->cnd_rpcFD);
cnd->cnd_rpcFD = -1;
XR_ConsoleMsg("CirioNubWorkerProc broke connection\n");
return TRUE;
}
}
static int
CirioNubSlaveProc(x)
unsigned x;
{
static struct sockaddr_in clearAddr;
struct sockaddr_in myAddr;
int fd = -1;
int ans, i;
CirioNubData d = (CirioNubData)(x);
short srchPort;
/* create socket */
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if( fd < 0 ) { ans = -1; goto Out; }
/* bind to specified address or search for unused one */
srchPort = ((short)(d->cnd_listenerPort));
if( srchPort == 0 ) srchPort = CIRIO_NUB_LISTENER_PORT;
for( i = 0; ; i++ ) {
myAddr = clearAddr;
myAddr.sin_family = AF_INET;
myAddr.sin_port = htons(srchPort);
ans = bind( fd, &myAddr, (sizeof myAddr) );
if( ans >= 0 ) break;
if( (d->cnd_listenerPort != 0) || (i >= 20) ) { ans = -2; goto Out; }
srchPort += 1;
}
d->cnd_listenerPort = srchPort;
ans = listen( fd, 2 );
if( ans < 0 ) { ans = -3; goto Out; }
d->cnd_listenerFD = fd; fd = -1;
if( d->cnd_initProc != NIL ) {
(*(d->cnd_initProc))(d->cnd_initClientData);
}
cnd = d;
XR_iope->iope_workerProc = CirioNubWorkerProc;
XR_sysArea->sa_dbData = ((XR_Pointer)(d));
XR_sysArea->sa_dbpid = XR_iope->iope_pid; /* ambush existing debugger! */
ans = d->cnd_listenerPort;
Out:
if( fd >= 0 ) (void)close(fd);
return ans;
}
/*
* Exported to CirioNubInstall.h
*/
CirioNubHandle
CirioNubCreateHandle(maxProcs, callBufBytes)
int maxProcs;
int callBufBytes;
{
CirioNubData d;
XR_Slave slave;
int nhdrs;
if( callBufBytes <= 0 ) callBufBytes = 2048;
if( (slave = XR_SlaveStart()) == NIL ) return(NIL);
for( nhdrs = 2; nhdrs < maxProcs; nhdrs <<= 1 ) {}
d = (CirioNubData) XR_malloc( sizeof(struct CirioNubDataRep)
+ (nhdrs-1)*sizeof(struct CirioNubProcEntry *) );
d->cnd_installed = FALSE;
d->cnd_slave = slave;
d->cnd_listenerPort = 0;
d->cnd_listenerFD = -1;
d->cnd_rpcFD = -1;
d->cnd_initProc = NIL;
d->cnd_initClientData = 0;
d->cnd_callBufBytes = callBufBytes;
d->cnd_callBuf = (int *) XR_malloc( callBufBytes );
d->cnd_numHdrs = nhdrs;
bzero( (char *)(d->cnd_procEntries),
(nhdrs)*sizeof(struct CirioNubProcEntry *) );
return( (CirioNubHandle)(d) );
}
static struct XR_MLRep defaultHandleLock;
static CirioNubHandle defaultHandle = NIL;
#define MAXPROCS_MIN 8
#define MAXPROCS_DEFAULT 128
#define CALLBUFBYTES_MIN 256
#define CALLBUFBYTES_DEFAULT 4096
CirioNubHandle
CirioNubGetDefaultHandle(maxProcs, callBufBytes)
int maxProcs;
int callBufBytes;
{
CirioNubHandle h;
if( (h = defaultHandle) == NIL ) {
if( maxProcs == 0 ) maxProcs = MAXPROCS_DEFAULT;
if( maxProcs < MAXPROCS_MIN ) maxProcs = MAXPROCS_MIN;
if( callBufBytes == 0 ) callBufBytes = CALLBUFBYTES_DEFAULT;
if( callBufBytes < CALLBUFBYTES_MIN ) callBufBytes = CALLBUFBYTES_MIN;
XR_MonitorEntry(&defaultHandleLock);
if( (h = defaultHandle) == NIL ) {
h = defaultHandle = CirioNubCreateHandle(maxProcs, callBufBytes);
}
XR_MonitorExit(&defaultHandleLock);
}
return h;
}
static struct XR_MLRep registrationLock;
int
CirioNubRegisterProc( h, procID, proc, data )
CirioNubHandle h;
int procID;
CirioNubProc proc;
char * data;
{
CirioNubData d = (CirioNubData)(h);
int hash;
struct CirioNubProcEntry *cnpe;
hash = HASH(d,procID);
cnpe = (struct CirioNubProcEntry *)XR_malloc( sizeof (*cnpe) );
if( cnpe == NIL ) return (-1);
cnpe->cnpe_procID = procID;
cnpe->cnpe_proc = proc;
cnpe->cnpe_clientData = data;
XR_MonitorEntry(®istrationLock);
cnpe->cnpe_next = d->cnd_procEntries[hash];
d->cnd_procEntries[hash] = cnpe;
XR_MonitorExit(®istrationLock);
return 0;
}
int
CirioNubRegisterCProc( h, procID, proc )
CirioNubHandle h;
int procID;
CirioNubProc proc;
{
return CirioNubRegisterProc( h, procID, proc, NIL );
}
int
CirioNubRegisterMProc( h, procID, mp )
CirioNubHandle h;
int procID;
XR_MesaProc mp;
{
return CirioNubRegisterProc( h, procID,
(CirioNubProc)(mp->mp_proc), (char *)(mp) );
}
int
CirioNubInstall(h, listenerPort, initProc, clientData)
CirioNubHandle h;
int listenerPort;
void (*initProc)(/* unsigned clientData */);
unsigned clientData;
{
int ans;
CirioNubData d;
d = (CirioNubData)(h);
if( d->cnd_installed ) return 0;
d->cnd_listenerPort = listenerPort;
d->cnd_initProc = initProc;
d->cnd_initClientData = clientData;
ans = XR_SlaveCall(
d->cnd_slave,
CirioNubSlaveProc,
(unsigned)(d),
XR_WAIT_FOREVER /* actually can't take very long */
);
if( ans == 0 ) d->cnd_installed = TRUE;
return ans;
}
/*
* Exported to CirioNubLocalProcs.h
*/
int
CirioNubLocalGetPort()
{
if( cnd == NIL ) return 0;
if( cnd->cnd_listenerPort <= 0 ) return 0;
return (cnd->cnd_listenerPort);
}